info: Added --show option
authorJoey Hess <joeyh@joeyh.name>
Wed, 13 Aug 2025 20:49:21 +0000 (16:49 -0400)
committerJoey Hess <joeyh@joeyh.name>
Wed, 13 Aug 2025 20:49:21 +0000 (16:49 -0400)
To pick which parts of the info to calculate and display.

Sponsored-by: Dartmouth College's DANDI project
CHANGELOG
Command/Info.hs
doc/git-annex-info.mdwn
doc/todo/make___96__info_--in_REMOTE__96___report_only_for_the_REMOTE.mdwn
doc/todo/make___96__info_--in_REMOTE__96___report_only_for_the_REMOTE/comment_2_8b0856a83f93bb3df8bbdeb1d7c9a82d._comment [new file with mode: 0644]

index 2d046bf671169d2ebd0714d21dde90c2a1285d1c..8a340af35ba35828e2e9973921d49ae89336c586 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,8 @@ git-annex (10.20250722) UNRELEASED; urgency=medium
   * S3: When initremote is given the name of a bucket that already exists,
     automatically set datacenter to the right value, rather than needing it
     to be explicitly set. (This needs aws-0.23)
+  * info: Added --show option to pick which parts of the info to calculate
+    and display.
   * Bump aws build dependency to 0.24.1.
   * stack.yaml: Update to lts-24.2.
 
index 3c0b7c030eacf99116d2d42cc43702b0e544b2ae..d2f690027a2e74328b3bff51312322c7dac1eb64 100644 (file)
@@ -1,6 +1,6 @@
 {- git-annex command
  -
- - Copyright 2011-2024 Joey Hess <id@joeyh.name>
+ - Copyright 2011-2025 Joey Hess <id@joeyh.name>
  -
  - Licensed under the GNU AGPL version 3 or higher.
  -}
@@ -55,7 +55,10 @@ import qualified Command.Unused
 import qualified Utility.RawFilePath as R
 
 -- a named computation that produces a statistic
-type Stat = StatState (Maybe (String, StatState String))
+data Stat = Stat
+       { statDesc :: String
+       , statComp :: StatState (Maybe (StatState String))
+       }
 
 -- data about a set of keys
 data KeyInfo = KeyInfo
@@ -116,6 +119,7 @@ data InfoOptions = InfoOptions
        , batchOption :: BatchMode
        , autoenableOption :: Bool
        , deadrepositoriesOption :: Bool
+       , showOption :: [String]
        }
 
 optParser :: CmdParamsDesc -> Parser InfoOptions
@@ -134,6 +138,10 @@ optParser desc = InfoOptions
                ( long "dead-repositories"
                <> help "list repositories that have been marked as dead"
                )
+       <*> many (strOption
+               ( long "show" <> metavar paramName
+               <> help "limit info output"
+               ))
 
 seek :: InfoOptions -> CommandSeek
 seek o = case batchOption o of
@@ -158,7 +166,7 @@ globalInfo o = do
        u <- getUUID
        whenM ((==) DeadTrusted <$> lookupTrust u) $
                earlyWarning "Warning: This repository is currently marked as dead."
-       stats <- selStats global_fast_stats global_slow_stats
+       stats <- selStats global_fast_stats global_slow_stats
        showCustom "info" (SeekInput []) $ do
                evalStateT (mapM_ showStat stats) (emptyStatInfo o)
                return True
@@ -211,7 +219,7 @@ noInfo s si msg = do
 
 dirInfo :: InfoOptions -> FilePath -> SeekInput -> Annex ()
 dirInfo o dir si = showCustom (unwords ["info", dir]) si $ do
-       stats <- selStats
+       stats <- selStats o
                (tostats (dir_name:tree_fast_stats True))
                (tostats tree_slow_stats)
        evalStateT (mapM_ showStat stats) =<< getDirStatInfo o dir
@@ -226,7 +234,7 @@ treeishInfo o t si = do
                Nothing -> noInfo t si
                        "not a directory or an annexed file or a treeish or a remote or a uuid"
                Just i -> showCustom (unwords ["info", t]) si $ do
-                       stats <- selStats 
+                       stats <- selStats o
                                (tostats (tree_name:tree_fast_stats False)) 
                                (tostats tree_slow_stats)
                        evalStateT (mapM_ showStat stats) i
@@ -247,7 +255,7 @@ remoteInfo :: InfoOptions -> Remote -> SeekInput -> Annex ()
 remoteInfo o r si = showCustom (unwords ["info", Remote.name r]) si $ do
        i <- map (\(k, v) -> simpleStat k (pure v)) <$> Remote.getInfo r
        let u = Remote.uuid r
-       l <- selStats 
+       l <- selStats o
                (uuid_fast_stats u ++ remote_fast_stats r ++ i)
                (uuid_slow_stats u)
        evalStateT (mapM_ showStat l) (emptyStatInfo o)
@@ -255,16 +263,21 @@ remoteInfo o r si = showCustom (unwords ["info", Remote.name r]) si $ do
 
 uuidInfo :: InfoOptions -> UUID -> SeekInput -> Annex ()
 uuidInfo o u si = showCustom (unwords ["info", fromUUID u]) si $ do
-       l <- selStats (uuid_fast_stats u) (uuid_slow_stats u)
+       l <- selStats (uuid_fast_stats u) (uuid_slow_stats u)
        evalStateT (mapM_ showStat l) (emptyStatInfo o)
        return True
 
-selStats :: [Stat] -> [Stat] -> Annex [Stat]
-selStats fast_stats slow_stats = do
-       fast <- Annex.getRead Annex.fast
-       return $ if fast
-               then fast_stats
-               else fast_stats ++ slow_stats
+selStats :: InfoOptions -> [Stat] -> [Stat] -> Annex [Stat]
+selStats o fast_stats slow_stats
+       | null (showOption o) = do
+               fast <- Annex.getRead Annex.fast
+               return $ if fast
+                       then fast_stats
+                       else fast_stats ++ slow_stats
+       | otherwise = return $
+               let wanted = S.fromList (showOption o)
+               in filter (\s -> S.member (statDesc s) wanted)
+                       (fast_stats ++ slow_stats)
 
 {- Order is significant. Less expensive operations, and operations
  - that share data go together.
@@ -337,14 +350,14 @@ uuid_slow_stats u = map (\s -> s u)
        ]
 
 stat :: String -> (String -> StatState String) -> Stat
-stat desc a = return $ Just (desc, a desc)
+stat desc a = Stat desc $ return $ Just $ a desc
 
 -- The json simply contains the same string that is displayed.
 simpleStat :: String -> StatState String -> Stat
 simpleStat desc getval = stat desc $ json id getval
 
-nostat :: Stat
-nostat = return Nothing
+nostat :: String -> Stat
+nostat desc = Stat desc $ return Nothing
 
 json :: ToJSON' j => (j -> String) -> StatState j -> String -> StatState String
 json fmt a desc = do
@@ -356,10 +369,10 @@ nojson :: StatState String -> String -> StatState String
 nojson a _ = a
 
 showStat :: Stat -> StatState ()
-showStat s = maybe noop calc =<< s
+showStat s = maybe noop calc =<< statComp s
   where
-       calc (desc, a) = do
-               (lift . showHeader . encodeBS) desc
+       calc a = do
+               (lift . showHeader . encodeBS) (statDesc s)
                lift . showRaw . encodeBS =<< a
 
 repo_list :: TrustLevel -> Stat
@@ -557,15 +570,16 @@ numcopies_stats = stat "numcopies stats" $ json fmt $
 
 reposizes_stats_tree :: Stat
 reposizes_stats_tree = reposizes_stats True "repositories containing these files"
-       =<< cachedRepoData
+       cachedRepoData
 
 reposizes_stats_global :: Stat
 reposizes_stats_global = reposizes_stats False "annex sizes of repositories" 
-       . repoData =<< cachedAllRepoData
+       (repoData <$> cachedAllRepoData)
 
-reposizes_stats :: Bool -> String -> M.Map UUID KeyInfo -> Stat
-reposizes_stats count desc m = stat desc $ nojson $ do
+reposizes_stats :: Bool -> String -> StatState (M.Map UUID KeyInfo) -> Stat
+reposizes_stats count desc getm = stat desc $ nojson $ do
        sizer <- mkSizer
+       m <- getm
        let l = map (\(u, kd) -> (u, sizer storageUnits True (sizeKeys kd))) $
                sortBy (flip (comparing (sizeKeys . snd))) $
                M.toList m
@@ -818,15 +832,16 @@ showSizeKeys d = do
                        " unknown size"
 
 staleSize :: String -> (Git.Repo -> OsPath) -> Stat
-staleSize label dirspec = go =<< lift (dirKeys dirspec)
+staleSize label dirspec = Stat label $ do
+       keys <- lift $ dirKeys dirspec  
+       onsize =<< sum <$> keysizes keys
   where
-       go [] = nostat
-       go keys = onsize =<< sum <$> keysizes keys
-       onsize 0 = nostat
-       onsize size = stat label $
-               json (++ aside "clean up with git-annex unused") $ do
+       onsize 0 = return Nothing
+       onsize size = return $ Just $
+               let val = do
                        sizer <- mkSizer
                        return $ sizer storageUnits False size
+               in json (++ aside "clean up with git-annex unused") val label
        keysizes keys = do
                dir <- lift $ fromRepo dirspec
                liftIO $ forM keys $ \k -> 
index 9b0e9715dfe21d4bb8f5a0b82a12898ed2915669..6e1cdd2dc6d3e77221ad47a4a0bce8b652a35ffc 100644 (file)
@@ -35,6 +35,14 @@ information.
 
 # OPTIONS
 
+* `--show=name`
+
+  Avoid info doing work to calculate things you don't need by specifying
+  what to show. This option can be specified more than once.
+
+  The name is the text before the ":" in the info output, eg
+  "local annex size" and "annex sizes of repositories".
+
 * `--fast`
 
   Only show the information that can be gathered quickly.
@@ -76,7 +84,8 @@ information.
 * matching options
 
   The [[git-annex-matching-options]](1) can be used to select what
-  to include in the statistics.
+  files to consider when operating on a directory. These options are
+  ignored when operating on other items.
 
 * Also the [[git-annex-common-options]](1) can be used.
 
index 8dac19951765c575594500f8ecb41c7c2ab4ac9e..629509727a10ed03613926958300879fd6392290 100644 (file)
@@ -38,3 +38,5 @@ with `--json` also correspondingly trimmed up.  Or it could potentially be a dif
 
 [[!meta author=yoh]]
 [[!tag projects/dandi]]
+
+> [[done]] --[[Joey]]
diff --git a/doc/todo/make___96__info_--in_REMOTE__96___report_only_for_the_REMOTE/comment_2_8b0856a83f93bb3df8bbdeb1d7c9a82d._comment b/doc/todo/make___96__info_--in_REMOTE__96___report_only_for_the_REMOTE/comment_2_8b0856a83f93bb3df8bbdeb1d7c9a82d._comment
new file mode 100644 (file)
index 0000000..86213fe
--- /dev/null
@@ -0,0 +1,7 @@
+[[!comment format=mdwn
+ username="joey"
+ subject="""comment 2"""
+ date="2025-08-13T20:48:13Z"
+ content="""
+Implemented `info --show`
+"""]]